package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.message.NewsAutoScanConstants;
import com.heima.common.constants.message.WmNewsMessageConstants;
import com.heima.common.constants.wemetia.WemetiaConstants;
import com.heima.model.admin.dtos.NewsAuthDto;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.media.dtos.WmNewsDto;
import com.heima.model.media.dtos.WmNewsPageReqDto;
import com.heima.model.media.dtos.WmNewsVo;
import com.heima.model.media.pojos.WmMaterial;
import com.heima.model.media.pojos.WmNews;
import com.heima.model.media.pojos.WmNewsMaterial;
import com.heima.model.media.pojos.WmUser;
import com.heima.utils.threadlocal.WmThreadLocalUtils;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsService;
import com.sun.xml.internal.fastinfoset.util.ValueArray;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.java2d.pipe.SpanIterator;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @作者 itcast
 * @创建日期 2020/9/24 9:46
 **/
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    @Value("${fdfs.url}")
    private String fileServerUrl;
    @Autowired
    WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    WmMaterialMapper wmMaterialMapper;
    @Override
    public ResponseResult findList(WmNewsPageReqDto dto) {
        WmUser user = WmThreadLocalUtils.getUser();
        if(user == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        // 1. 检查参数
        if(dto == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();
        // 2. 查询数据
        // 2.1 封装分页条件
        IPage<WmNews> pageParam = new Page(dto.getPage(),dto.getSize());
        // 2.2 封装查询条件_文章状态
        LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(dto.getStatus()!=null){
            lambdaQueryWrapper.eq(WmNews::getStatus,dto.getStatus());
        }
        // 2.3 封装查询条件_关键字
        if(StringUtils.isNotEmpty(dto.getKeyword())){
            lambdaQueryWrapper.like(WmNews::getTitle,dto.getKeyword());
        }
        // 2.4 封装查询条件_频道id
        if(dto.getChannelId()!=null){
            lambdaQueryWrapper.eq(WmNews::getChannelId,dto.getChannelId());
        }
        // 2.5 封装查询条件_发布开始和结束时间
        if(dto.getBeginPubDate()!=null && dto.getEndPubDate()!=null){
            lambdaQueryWrapper.between(WmNews::getPublishTime,dto.getBeginPubDate(),dto.getEndPubDate());
        }
        // 2.6 封装查询条件_登录用户ID
        lambdaQueryWrapper.eq(WmNews::getUserId,user.getId());
        // 创建时间降序
        lambdaQueryWrapper.orderByDesc(WmNews::getCreatedTime);
        // 2.6 执行查询
        IPage<WmNews> pageResult = page(pageParam, lambdaQueryWrapper);

        // 3. 结果封装
        PageResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(),pageResult.getTotal());
        responseResult.setData(pageResult.getRecords());
        responseResult.setHost(fileServerUrl);
        return responseResult;
    }
    @Transactional
    @Override
    public ResponseResult saveNews(WmNewsDto dto, Short isSubmit) {
        // 1. 检查参数
        if(dto == null || StringUtils.isEmpty(dto.getContent())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 2. 保存或修改文章
        WmNews wmNews = new WmNews();
        // 将参数中的属性值拷贝到wmNews中
        BeanUtils.copyProperties(dto,wmNews);
        if(WemetiaConstants.WM_NEWS_TYPE_AUTO.equals(dto.getType())){
            wmNews.setType(null);
        }
        if(dto.getImages()!=null && dto.getImages().size() > 0){
            List<String> urlList = dto.getImages()
                    .stream()
                    .map(str -> str.replace(fileServerUrl, ""))
                    .collect(Collectors.toList());
            wmNews.setImages(StringUtils.join(urlList,","));
        }
        saveWmNews(wmNews,isSubmit);
        // 3. 关联文章与素材的关系
        String content = dto.getContent();
        List<Map> list = JSON.parseArray(content, Map.class);
        List<String> materials = getUrlFromContent(list);
        // 3.1 关联内容中的图片与素材的关系
        if(isSubmit == WmNews.Status.SUBMIT.getCode() && materials.size()>0){
            ResponseResult responseResult = saveRelativeInfoForContent(materials,wmNews.getId());
            if (responseResult!=null) {
                return responseResult;
            }
        }
        // 3.2 关联封面中的图片与素材的关系,设置wm_news的type,自动
        if(isSubmit == WmNews.Status.SUBMIT.getCode()){
            ResponseResult responseResult = saveRelativeInfoForCover(dto,materials,wmNews);
            if (responseResult!=null) {
                return responseResult;
            }
        }
        return null;
    }
    @Override
    public ResponseResult findWmNewsById(Integer newsId) {
        // 判断参数
        if(newsId == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 查询文章
        WmNews wmNews = getById(newsId);
        if(wmNews == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"文章信息不存在");
        }
        // 结果返回
        ResponseResult responseResult = ResponseResult.okResult(wmNews);
        responseResult.setHost(fileServerUrl);
        return responseResult;
    }

    @Override
    public ResponseResult delNews(Integer id) {
        // 参数检查
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews  = getById(id);
        if(wmNews == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"文章信息不存在");
        }
        // 状态已发布，并且以上架的文章无法删除
        if(wmNews.getStatus() == WmNews.Status.PUBLISHED.getCode() && wmNews.getEnable() == WemetiaConstants.WM_NEWS_ENABLE_UP){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"文章已发布，无法删除");
        }
        // 删除文章前，先删除关联数据
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,id));
        removeById(id);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        // 判断参数
        if(dto == null || dto.getId()==null || (dto.getEnable()!=0 && dto.getEnable()!=1)){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews = getById(dto.getId());
        if(wmNews == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if(wmNews.getStatus() != WmNews.Status.PUBLISHED.getCode()){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"当前文章不是发布状态，不能上下架");
        }

        // 上下架操作
        update(
                Wrappers.<WmNews>lambdaUpdate()
                        .set(WmNews::getEnable,dto.getEnable())
                        .eq(WmNews::getId,dto.getId())
                        .eq(WmNews::getUserId,WmThreadLocalUtils.getUser().getId())
        );
        if(wmNews.getArticleId()!=null){
            Map<String,Object> mesMap = new HashMap<>();
            mesMap.put("enable",dto.getEnable());
            mesMap.put("articleId",wmNews.getArticleId());
            // 向指定主题发送上架下架的消息
            kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC,JSON.toJSONString(mesMap));
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
    @Override
    public List<Integer> findRelease() {
        // 查询  文章status为8 且发布时间 小于等于当前时间的所有文章
        List<WmNews> list = list(
                Wrappers.<WmNews>lambdaQuery()
                        .in(WmNews::getStatus, WmNews.Status.ADMIN_SUCCESS.getCode(),WmNews.Status.SUCCESS.getCode())
                        .le(WmNews::getPublishTime, new Date()));
        // 筛选出集合中的id
        List<Integer> idList = list.stream().map(WmNews::getId).collect(Collectors.toList());
        return idList;
    }
    @Autowired
    WmNewsMapper wmNewsMapper;
    @Override
    public ResponseResult findListAndPage(NewsAuthDto dto) {
        // 1. 检查参数
        if (dto==null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();
        int page = dto.getPage();
        // 因为是自己写分页了 所以处理下page的设置
        dto.setPage((page-1)*dto.getSize());
        dto.setTitle("%" +dto.getTitle() +"%");
        // 分页查询
        List<WmNewsVo> list = wmNewsMapper.findListAndPage(dto);
        int count = wmNewsMapper.findListCount(dto);
        // 封装结果
        PageResponseResult responseResult = new PageResponseResult(page,dto.getSize(),(long) count);
        responseResult.setData(list);
        return responseResult;
    }
    @Autowired
    private WmUserMapper wmUserMapper;
    @Override
    public WmNewsVo findWmNewsVo(Integer id) {
        // 查询文章信息
        WmNews wmNews = getById(id);
        // 查询作者
        WmUser wmUser = null;
        if(wmNews!=null && wmNews.getUserId()!=null){
            wmUser = wmUserMapper.selectById(wmNews.getUserId());
        }
        // 封装vo信息返回
        WmNewsVo wmNewsVo = new WmNewsVo();
        BeanUtils.copyProperties(wmNews,wmNewsVo);
        if(wmUser!=null){
            wmNewsVo.setAuthorName(wmUser.getName());
        }
        return wmNewsVo;
    }

    /**
     * 设置封面图片与素材间的关系
     * @param dto
     * @param materials
     * @param wmNews
     * @return
     */
    private ResponseResult saveRelativeInfoForCover(WmNewsDto dto, List<String> materials, WmNews wmNews) {
        // 1. 获取请求中封面图片集合
        List<String> images = dto.getImages(); // 封面图片列表
        // 2. 自动匹配封面的处理
        if(dto.getType().equals(WemetiaConstants.WM_NEWS_TYPE_AUTO)){
            if(materials.size()>0 && materials.size()<=2){
                // 内容中图片数量小于等于2张 设置为单图
                wmNews.setType(WemetiaConstants.WM_NEWS_SINGLE_IMAGE);
                images = materials.stream().limit(1).collect(Collectors.toList());;
            }else if(materials.size()>3){
                // 内容中图片数量大于2张 设置为多图(3张)
                wmNews.setType(WemetiaConstants.WM_NEWS_MANY_IMAGE);
                images = materials.stream().limit(3).collect(Collectors.toList());;
            }else {
                // 内容中没有图片的 设置为无图
                wmNews.setType(WemetiaConstants.WM_NEWS_NONE_IMAGE);
            }
            // 修改文章信息
            if(images!=null&&images.size()>0){
                // 将图片路径中的前缀serverUrl替换掉
                images = images.stream().map(str -> str.replace(fileServerUrl, "")).collect(Collectors.toList());
                wmNews.setImages(StringUtils.join(images,","));
            }
            updateById(wmNews);
        }
        // 保存封面图片与素材的关系
        if (images !=null && images.size()>0){
            images = images.stream().map(str -> str.replace(fileServerUrl, "")).collect(Collectors.toList());
            return saveRelativeInfo(images,wmNews.getId(),WemetiaConstants.WM_COVER_REFERENCE);
        }
        return null;
    }

    /**
     * 内容中涉及素材 的关联关系保存
     * @param materials 涉及的素材图片列表
     * @param newsId 文章ID
     * @return
     */
    private ResponseResult saveRelativeInfoForContent(List<String> materials, Integer newsId) {

        return saveRelativeInfo(materials,newsId,WemetiaConstants.WM_CONTENT_REFERENCE);
    }

    private ResponseResult saveRelativeInfo(List<String> materials, Integer newsId, Short type) {
        //1. 根据图片列表=>获取数据库中的素材信息
        LambdaQueryWrapper<WmMaterial> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(WmMaterial::getUrl,materials);
        lambdaQueryWrapper.eq(WmMaterial::getUserId,WmThreadLocalUtils.getUser().getId());
        List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(lambdaQueryWrapper);

        //2. 在素材列表中，提取出素材ID
        List<String> materialIds = new ArrayList<>(); // 素材ID列表
        if(wmMaterials!=null && wmMaterials.size()>0){
            Map<String, Integer> uriIdMap = wmMaterials.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
            for (String imgUrl : materials ) {
                String materialId = String.valueOf(uriIdMap.get(imgUrl));
                if("null".equals(materialId)){
                    return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"关联图片已失效");
                }
                materialIds.add(materialId);
            }
        }
        //3. 批量保存
        wmNewsMaterialMapper.saveRelations(materialIds,newsId,type);
        return null;
    }


    /**
     * 在内容中 提取出所有图片路径
     * @param list
     * @return
     */
    private List<String> getUrlFromContent(List<Map> list) {
        return list.stream()
                    .filter(map -> map.get("type").equals(WemetiaConstants.WM_NEWS_TYPE_IMAGE))
                    .map(map -> {
                        String imgUrl = (String) map.get("value");
                        imgUrl = imgUrl.replace(fileServerUrl,"");
                        return imgUrl;
                    })
                    .collect(Collectors.toList());
    }

    @Autowired
    KafkaTemplate<String,String> kafkaTemplate;

    /**
     * 保存或修改文章表信息
     * @param wmNews
     * @param isSubmit 0 草稿, 1 发布待审核
     */
    private void saveWmNews(WmNews wmNews, Short isSubmit) {
        wmNews.setStatus(isSubmit);
        wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short) 1); // 默认上架
        boolean flag = false;
        if(wmNews.getId() == null){
            // 添加
            flag = save(wmNews);
        }else {
            // 修改
            // 先删除素材与文章的关系
            LambdaQueryWrapper<WmNewsMaterial> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(WmNewsMaterial::getNewsId,wmNews.getId());
            wmNewsMaterialMapper.delete(lambdaQueryWrapper);
            flag = updateById(wmNews);
        }
        // 自媒体人新发布的文章，或是修改的文章 都需要admin端进行审核
        if(flag){
            kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC,JSON.toJSONString(wmNews.getId()));
        }
    }
}
